package com.gqr.lock.lock;

import java.util.Random;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 演示公平和不公平两种情况
 */
public class FairLock {

    public static void main(String[] args) {
        PrintQueue printQueue = new PrintQueue();
        Thread thread[] = new Thread[10];
        for (int i = 0; i < 10; i++) {
            thread[i] = new Thread(new Job(printQueue));
        }
        for (int i = 0; i < 10; i++) {
            thread[i].start();
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

}

class Job implements Runnable {
    PrintQueue printQueue;

    public Job(PrintQueue printQueue) {
        this.printQueue = printQueue;
    }

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + "开始打印");
        printQueue.printJob(new Object());
        System.out.println(Thread.currentThread().getName() + "打印完毕");
    }
}

class PrintQueue {
    private Lock queueLock = new ReentrantLock(false);

    public void printJob(Object docuemnt) {
        /**
         * 公平锁情况下 线程0先获取锁  线程1-9在排队
         */
        /**
         * 非公平锁情况下  线程0先获取锁 打印完第一个任务 就直接打印第二个任务了
         */
        queueLock.lock();
        try {
            int duration = new Random().nextInt(5) + 1;
            System.out.println(Thread.currentThread().getName() + "正在打印第一个任务，需要" + duration+"秒");
            Thread.sleep(duration * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            /**
             * 线程0 释放锁  线程1-9 依次获取到锁
             */
            queueLock.unlock();
        }
        System.out.println(Thread.currentThread().getName() +"想第二次打印，却被阻塞");
        /**
         * 公平锁情况下 线程0 （线程1-9 一样是打印完第一个任务 就想执行第二个任务） 打印第一个任务后 依旧得获取锁才能执行第二个打印任务
         *          但是此时等待队列里已经有1-9线程在等待 线程0需要继续加入等待队列并且排在9的后面
         *          只有当线程9打印完第一个任务后 释放了锁 此时线程0才能打印第二个任务 （线程1-9同理）
         */
        queueLock.lock();
        try {
            int duration = new Random().nextInt(5) + 1;
            System.out.println(Thread.currentThread().getName() + "正在打印第二个任务，需要" + duration+"秒");
            Thread.sleep(duration * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            queueLock.unlock();
        }
    }
}